﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ServiceModel;
using Collab.Common.Contacts;
using Collab.Services.Remote.WebserviceProxy.ServiceProxy;

namespace Collab.Services.Remote.WebserviceProxy
{
    public class Repository : IRepository
    {

        private WebServiceClient client;

        private event EventHandler editUserCallback;
        private event EventHandler deleteContactCallback;
        private event EventHandler searchUsersCallback;
        private event EventHandler addToContactsCallback;
        private event EventHandler getUserCallback;
        private event EventHandler inviteToGroupCallback;

        private AsyncCallback GetUserAsyncCompleted;
        private AsyncCallback EditUserAsyncCompleted;
        private AsyncCallback AuthenticateUserAsyncCompleted;
        private AsyncCallback DeleteContactAsyncCompleted;
        private AsyncCallback SearchUsersAsyncCompleted;
        private AsyncCallback AddToContactsAsyncCompleted;
        private AsyncCallback InviteToGroupCompleted;

        /// <summary>
        /// Gets or sets the client.
        /// </summary>
        /// <value>The client.</value>
        public WebServiceClient Client 
        {
            get
            {
                return this.client;
            }
            private set
            {
                if (this.client != value)
                    this.client = value;
            }
        }

        public Repository()
        {
            // TODO: Get it to use the default configuration in app.config instead.
            var binding = new BasicHttpBinding();
            EndpointAddress address = new EndpointAddress("http://api.collab.asthena.com/CollabServiceLibrary.WebService.svc");
            
            // For debugging of local WebServer
            //EndpointAddress address = new EndpointAddress("http://localhost:8732/Design_Time_Addresses/CollabServiceLibrary/WebService/");
            this.client = new WebServiceClient(binding, address);


            // Initialize eventhandlers
            this.client.SearchUsersCompleted += new EventHandler<SearchUsersCompletedEventArgs>(client_SearchUsersCompleted);
            this.client.GetUserCompleted += new EventHandler<GetUserCompletedEventArgs>(client_GetUserCompleted);
            this.client.EditUserCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_EditUserCompleted);
            this.client.DeleteContactCompleted += new EventHandler<DeleteContactCompletedEventArgs>(client_DeleteContactCompleted);
            this.client.AddUserContactCompleted += new EventHandler<AddUserContactCompletedEventArgs>(client_AddUserContactCompleted);
            this.client.CreateGroupInvitationCompleted += new EventHandler<CreateGroupInvitationCompletedEventArgs>(client_CreateGroupInvitationCompleted);
        }

        

        /// <summary>
        /// Authenticates the user.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <returns></returns>
        public bool AuthenticateUser(string username, string password)
        {

            // TODO should use ApplicationService instead
            return client.AuthenticateUser(username, password);
        }

        /// <summary>
        /// Sets the users status status.
        /// </summary>
        /// <param name="userId">The user id.</param>
        /// <param name="ip">The ip.</param>
        /// <param name="port">The port.</param>
        public void SetStatus(Guid userId, string ip, int port)
        {
            client.SetStatus(userId, ip, port);
        }

        /// <summary>
        /// Gets the online statuses for a userId
        /// </summary>
        /// <param name="userId">The user id.</param>
        /// <returns></returns>
        public IEnumerable<OnlineStatus> GetOnlineStatuses(Guid userId)
        {
            return client.GetOnlineStatuses(userId);
        }

        /// <summary>
        /// Gets the recent online status.
        /// </summary>
        /// <param name="userId">The user id.</param>
        /// <returns></returns>
        public OnlineStatus GetRecentOnlineStatus(Guid userId)
        {
            return client.GetRecentOnlineStatus(userId);
        }

        /// <summary>
        /// Retrives session invites from the web service
        /// </summary>
        /// <param name="userId">The user id.</param>
        /// <returns></returns>
        public IEnumerable<SessionInvite> GetSessionInvites(Guid userId)
        {
            ObservableCollection<SessionInvite> sessionInvites = new ObservableCollection<SessionInvite>();

            try
            {
                sessionInvites = client.GetSessionInvites(userId);
            }
            catch (FaultException ex)
            {
                // log exception

            }

            return sessionInvites;
            
        }

        /// <summary>
        /// Creates a session invite on the web service
        /// </summary>
        /// <param name="invitingUserId">The inviting user id.</param>
        /// <param name="invitedUserId">The invited user id.</param>
        /// <param name="message">The message.</param>
        /// <param name="invitingUserIP">The inviting user IP.</param>
        public void CreateSessionInvite(Guid invitingUserId, Guid invitedUserId, string message, string invitingUserIP)
        {
            client.CreateSessionInvite(invitingUserId, invitedUserId, message, invitingUserIP);
        }

        /// <summary>
        /// Updates the user asynchrounusly.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="callback">The callback to the ViewModel</param>
        public void EditUserAsync(User user, EventHandler callback)
        {
            client.EditUserAsync(user);
            editUserCallback = callback;
        }

        /// <summary>
        /// Handles the EditUserCompleted event of the client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.AsyncCompletedEventArgs"/> instance containing the event data.</param>
        void client_EditUserCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            CallbackResult<bool> callbackResult = new CallbackResult<bool> { IsError = false };

            if (e.Error == null)
            {
                callbackResult.IsError = false;
                callbackResult.Object = true;
            }
            else
            {
                callbackResult.IsError = true;
                callbackResult.ErrorMessage = e.Error.Message;
            }

            editUserCallback.Invoke(callbackResult, new EventArgs());
        }

        /// <summary>
        /// Get the user corresponding to the username async.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <param name="callback">The callback to the ViewModel</param>
        public void GetUserAsync(string username, EventHandler callback)
        {

            client.GetUserAsync(username);
            getUserCallback = callback;
        }

        /// <summary>
        /// Handles the GetUserCompleted event of the client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Collab.Services.Remote.WebserviceProxy.ServiceProxy.GetUserCompletedEventArgs"/> instance containing the event data.</param>
        void client_GetUserCompleted(object sender, GetUserCompletedEventArgs e)
        {
            CallbackResult<User> callbackResult = new CallbackResult<User> { IsError = false };

            if (e.Error == null)
            {
                callbackResult.Object = e.Result;
            }
            else
            {
                callbackResult.IsError = true;
                callbackResult.ErrorMessage = e.Error.Message;
            }

            getUserCallback.Invoke(callbackResult, new EventArgs());
        }

        /// <summary>
        /// Gets the user.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <returns></returns>
        public User GetUser(string username)
        {
            return client.GetUser(username);
        }

        /// <summary>
        /// Deletes the contact async.
        /// </summary>
        /// <param name="contact">The contact.</param>
        /// <param name="user">The user.</param>
        /// <param name="callback">The callback.</param>
        public void DeleteContactAsync(Contact contact, User user, EventHandler callback)
        {
            deleteContactCallback = callback;
            client.BeginDeleteContact(contact, user, DeleteContactAsyncCompleted, null);
        }

        /// <summary>
        /// Handles the DeleteContactCompleted event of the client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Collab.Services.Remote.WebserviceProxy.ServiceProxy.DeleteContactCompletedEventArgs"/> instance containing the event data.</param>
        void client_DeleteContactCompleted(object sender, DeleteContactCompletedEventArgs e)
        {
            CallbackResult<Contact> callbackResult = new CallbackResult<Contact> { IsError = false };

            if (e.Error == null)
            {
                callbackResult.Object = e.Result;
            }
            else
            {
                callbackResult.IsError = true;
                callbackResult.ErrorMessage = e.Error.Message;
            }

            deleteContactCallback.Invoke(callbackResult, new EventArgs());
        }

        /// <summary>
        /// Searches the users async.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <param name="callback">The callback.</param>
        public void SearchUsersAsync(string query, EventHandler callback)
        {
            searchUsersCallback = callback;
            client.SearchUsersAsync(query);
        }

        /// <summary>
        /// Handles the SearchUsersCompleted event of the client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Collab.Services.Remote.WebserviceProxy.ServiceProxy.SearchUsersCompletedEventArgs"/> instance containing the event data.</param>
        void client_SearchUsersCompleted(object sender, SearchUsersCompletedEventArgs e)
        {
            CallbackResult<ObservableCollection<Contact>> callbackResult = new CallbackResult<ObservableCollection<Contact>> { IsError = false };

            if (e.Error == null)
            {
                callbackResult.Object = e.Result;
            }
            else
            {
                callbackResult.IsError = true;
                callbackResult.ErrorMessage = e.Error.Message;
            }

            searchUsersCallback.Invoke(callbackResult, new EventArgs());
        }

        /// <summary>
        /// Adds to conacts async.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="newContact">The new contact.</param>
        /// <param name="callback">The callback.</param>
        public void AddToConactsAsync(User user, Contact newContact, EventHandler callback)
        {
            addToContactsCallback = callback;
            client.BeginAddUserContact(user, newContact, AddToContactsAsyncCompleted, null);
        }

        /// <summary>
        /// Handles the AddUserContactCompleted event of the client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Collab.Services.Remote.WebserviceProxy.ServiceProxy.AddUserContactCompletedEventArgs"/> instance containing the event data.</param>
        void client_AddUserContactCompleted(object sender, AddUserContactCompletedEventArgs e)
        {
            CallbackResult<Contact> callback = new CallbackResult<Contact> { IsError = false };

            if (e.Error == null)
            {
                callback.Object = e.Result;
            }
            else
            {
                callback.IsError = true;
                callback.ErrorMessage = e.Error.Message;
            }

            addToContactsCallback.Invoke(callback, new EventArgs());
        }

        /// <summary>
        /// Inivtes to group async.
        /// </summary>
        /// <param name="invite">The invite.</param>
        /// <param name="callback">The callback.</param>
        public void InivteToGroupAsync(GroupInvite invite, EventHandler callback)
        {
            client.CreateGroupInvitationAsync(invite);
            inviteToGroupCallback = callback;
        }

        /// <summary>
        /// Handles the CreateGroupInvitationCompleted event of the client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Collab.Services.Remote.WebserviceProxy.ServiceProxy.CreateGroupInvitationCompletedEventArgs"/> instance containing the event data.</param>
        void client_CreateGroupInvitationCompleted(object sender, CreateGroupInvitationCompletedEventArgs e)
        {
            CallbackResult<GroupInvite> callbackResult = new CallbackResult<GroupInvite> { IsError = false };

            if (e.Error == null)
            {
                callbackResult.Object = e.Result;
            }
            else
            {
                callbackResult.IsError = true;
                callbackResult.ErrorMessage = e.Error.Message;
            }

            inviteToGroupCallback.Invoke(callbackResult, new EventArgs());
            
        }

    }
}
